package main

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"sync"
	"text/tabwriter"
	"time"

	"monitor/config"
)

// ANSI控制代码
const (
	colorReset  = "\033[0m"
	colorRed    = "\033[31m"
	colorGreen  = "\033[32m"
	colorYellow = "\033[33m"
	cursorHide  = "\033[?25l"
	cursorShow  = "\033[?25h"
	cursorHome  = "\033[H"
	clearScreen = "\033[2J"
	clearLine   = "\033[2K"
	moveUp      = "\033[1A"
)

// 告警阈值
const (
	warningThreshold = 80.0 // 80%
)

// 刷新间隔（秒）
const (
	refreshInterval = 3
	noData          = " "
)

// 系统配置
var sysConfig = config.GetDefaultConfig()

// 配置文件结构
type Config struct {
	Servers []Server `json:"servers"`
}

// 服务器配置
type Server struct {
	Name string `json:"name"`
	IP   string `json:"ip"`
	Port int    `json:"port"` // 可选，默认为1680
}

// 系统信息结构体（与agent模块保持一致）
type SystemInfo struct {
	CPU       float64 `json:"cpu"`        // CPU使用率（百分比）
	Mem       uint64  `json:"mem"`        // 当前内存占用（字节）
	MemTotal  uint64  `json:"mem_total"`  // 总内存（字节）
	Disk      uint64  `json:"disk"`       // 当前硬盘占用（字节）
	DiskTotal uint64  `json:"disk_total"` // 硬盘总量（字节）
}

// 服务器状态
type ServerStatus struct {
	Server     Server
	SystemInfo SystemInfo
	Online     bool
	Error      string
	Latency    time.Duration
	RWMutex    sync.RWMutex // 添加读写锁，用于独立刷新数据
}

// 读取配置文件
func loadConfig(path string) (Config, error) {
	var config Config
	file, err := os.Open(path)
	if err != nil {
		return config, fmt.Errorf("打开配置文件失败: %v", err)
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	if err := decoder.Decode(&config); err != nil {
		return config, fmt.Errorf("解析配置文件失败: %v", err)
	}

	// 设置默认端口
	for i := range config.Servers {
		if config.Servers[i].Port == 0 {
			config.Servers[i].Port = 1680
		}
	}

	return config, nil
}

// 生成签名
func generateSign(timestamp string) string {
	data := timestamp + config.StaticKey + sysConfig.AuthKey
	hash := md5.Sum([]byte(data))
	return hex.EncodeToString(hash[:])
}

// 更新服务器状态
func updateServerStatus(status *ServerStatus) {
	beginTime := time.Now()

	// 生成时间戳和签名
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
	sign := generateSign(timestamp)

	// 构建请求URL
	server := status.Server
	url := fmt.Sprintf("http://%s:%d/?time=%s&sign=%s", server.IP, server.Port, timestamp, sign)

	// 发送请求
	client := &http.Client{
		Timeout: 5 * time.Second, // 设置超时时间
	}
	resp, err := client.Get(url)

	status.RWMutex.Lock()
	defer status.RWMutex.Unlock()

	status.Latency = time.Since(beginTime)

	if err != nil {
		status.Online = false
		status.Error = fmt.Sprintf("请求失败: %v", err)
		return
	}
	defer resp.Body.Close()

	// 检查响应状态码
	if resp.StatusCode != http.StatusOK {
		status.Online = false
		status.Error = fmt.Sprintf("服务器返回错误: %s", resp.Status)
		return
	}

	// 解析响应
	var info SystemInfo
	if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
		status.Online = false
		status.Error = "解析响应失败"
		return
	}

	// 成功获取数据，更新结构体内的值
	status.SystemInfo = info
	status.Online = true
	status.Error = ""
}

// 格式化字节大小为人类可读格式
func formatBytes(bytes uint64) string {
	const unit = 1024
	if bytes < unit {
		return fmt.Sprintf("%d B", bytes)
	}
	div, exp := uint64(unit), 0
	for n := bytes / unit; n >= unit; n /= unit {
		div *= unit
		exp++
	}
	return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}

// 格式化百分比，如果超过阈值则标红
func formatPercent(value float64) string {
	if value >= warningThreshold {
		return fmt.Sprintf("%s%.1f%%%s", colorRed, value, colorReset)
	}
	return fmt.Sprintf("%.1f%%", value)
}

// 格式化带颜色的使用率字符串
func formatUsageWithColor(used, total uint64) string {
	usedStr := formatBytes(used)
	totalStr := formatBytes(total)
	usage := float64(used) / float64(total) * 100

	var color string
	if usage >= warningThreshold {
		color = colorRed
	} else if usage >= 30 {
		color = colorYellow
	} else {
		color = colorGreen
	}
	return fmt.Sprintf("%s/%s (%s%.1f%%%s)",
		usedStr,
		totalStr,
		color,
		usage,
		colorReset)
}

// 初始化终端显示
func initTerminal() {
	fmt.Print(cursorHide)
}

// 恢复终端显示
func restoreTerminal() {
	fmt.Print(cursorShow)
}

// 准备刷新显示 - 只刷新服务器内容部分
func prepareRefresh(lines int) {
	for i := 0; i < lines; i++ {
		fmt.Print(moveUp)
		fmt.Print(clearLine)
	}
}

// 显示服务器状态表格
func displayStatusTable(statuses []*ServerStatus) {
	// 创建表格写入器
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)

	// 写入数据行
	for _, status := range statuses {
		status.RWMutex.RLock()
		defer status.RWMutex.RUnlock()

		statusStr := noData
		cpuStr := noData
		memStr := noData
		diskStr := noData
		latency := noData

		if status.Online {
			statusStr = fmt.Sprintf("%s在线%s", colorGreen, colorReset) // 在线为绿色
			cpuStr = formatPercent(status.SystemInfo.CPU)
			memStr = formatUsageWithColor(status.SystemInfo.Mem, status.SystemInfo.MemTotal)
			diskStr = formatUsageWithColor(status.SystemInfo.Disk, status.SystemInfo.DiskTotal)
			latency = fmt.Sprintf("%d ms", status.Latency.Milliseconds())
		} else {
			statusStr = fmt.Sprintf("%s离线%s", colorRed, colorReset) // 离线为红色
			latency = status.Error
			if len(latency) > 60 {
				latency = latency[:60] + "..."
			}
		}

		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n",
			status.Server.Name,
			statusStr,
			cpuStr,
			memStr,
			diskStr,
			latency)
	}

	// 刷新写入器
	w.Flush()
}

// 数据获取协程函数
func fetchServerDataRoutine(statuses []*ServerStatus) {
	for i := range statuses {
		status := statuses[i]
		go func() {
			ticker := time.NewTicker(refreshInterval * time.Second)
			defer ticker.Stop()

			for range ticker.C {
				updateServerStatus(status)
			}
		}()
	}
}

func main() {
	// 读取配置文件
	config, err := loadConfig("config.json")
	if err != nil {
		log.Fatalf("加载配置失败: %v", err)
	}

	if len(config.Servers) == 0 {
		log.Fatalf("配置文件中没有服务器信息")
	}

	// 初始化终端
	initTerminal()
	defer restoreTerminal()

	// 初始清屏（类似top命令的效果）
	fmt.Print(clearScreen)
	fmt.Print(cursorHome)

	// 共享的服务器状态数据和互斥锁
	statuses := make([]*ServerStatus, len(config.Servers))

	// 初始化服务器信息
	for i, server := range config.Servers {
		statuses[i] = &ServerStatus{}
		statuses[i].Server = server
	}

	// 启动数据获取协程
	go fetchServerDataRoutine(statuses)

	totalLines := len(config.Servers) + 2 // 服务器数 + 第一行 + 分隔线

	for {
		// 显示固定的第一行信息
		fmt.Printf("服务器: %d | 刷新时间: %s | 按 Ctrl+C 退出\n",
			len(config.Servers), time.Now().Format("2006-01-02 15:04:05"))
		// 显示固定的第二行分隔符
		fmt.Println("-----------------------------------------------------------------------------")

		// 不再需要外层互斥锁，每个ServerStatus有自己的读写锁
		displayStatusTable(statuses)

		time.Sleep(time.Second)
		prepareRefresh(totalLines)
	}
}
